home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Sample 2.4 Think C distribution / rpp.c < prev    next >
Text File  |  1990-08-29  |  63KB  |  2,114 lines

  1. /*______________________________________________________________________
  2.  
  3.     rpp.c - Report Printing Module.
  4.     
  5.     Copyright © 1988, 1989, 1990 Northwestern University.  Permission is granted
  6.     to use this code in your own projects, provided you give credit to both
  7.     John Norstad and Northwestern University in your about box or document.
  8.     
  9.     This reusable module implements the printing of reports.
  10.     
  11.     All the code is placed in its own segment named "rpp".
  12. _____________________________________________________________________*/
  13.  
  14. #include    <string.h>
  15. #include    <ctype.h>
  16.  
  17. #include "rpp.h"
  18. #include "utl.h"
  19. #include "doc.h"
  20.  
  21. #define normal 0            /* Think C doesn't know what "normal" is. */
  22. #define nil 0
  23.  
  24. /*______________________________________________________________________
  25.  
  26.     Globals.
  27. _____________________________________________________________________*/
  28.  
  29.  
  30. static Rect            PrintBox;            /* box enclosing text */
  31. static short        PrintBoxHeight;    /* print box height */
  32. static short        PrintBoxWidth;        /* print box width */
  33. static short        FirstPage;            /* first page number to print */
  34. static short        LastPage;            /* last page number to print */
  35. static Str255        NowDate;                /* current date */
  36. static Str255        NowTime;                /* current time */
  37. static short        TitleSize;            /* font size for headers */
  38. static short        TconCompute = 0;    /* 0 if tcon width variables not yet computed, 
  39.                                                     else 1 */
  40. static Boolean        TruncateRight;        /* true if print box too narrow */
  41. static Boolean        TruncateBottom;    /* true if print box too short */
  42.  
  43. /* Page break array for type 0 reports.
  44.     
  45.     (**Breaks0)[n] = info for page FirstPage+n,
  46.     for n = 0 through LastPage-FirstPage.
  47.     
  48. */
  49.  
  50. typedef struct Break0Info {
  51.     short                firstLine;            /* line number of first line on page */
  52.     short                numLines;            /* number of lines on page */
  53. } Break0Info;
  54.  
  55. static Break0Info        (**Breaks0)[];        /* handle to page break info */
  56.  
  57. /* Page break array for type 1 reports.
  58.     
  59.     (**Breaks1)[n] = info for page n,
  60.     for n = 1 through the total number of pages in the document.
  61.     
  62.     Note that for type 1 reports we build and keep the entire page break
  63.     array, not just the portion from FirstPage through LastPage.  This is
  64.     because the entire array is needed to print the table of contents.
  65.     
  66. */
  67.  
  68. typedef struct Break1Info {
  69.     short                auxInxB;            /* index in aux array of beginning
  70.                                                 of page */
  71.     short                offsetB;            /* offset in STR# resource of beginning
  72.                                                 of page */
  73.     short                auxInx;            /* index in aux array of first non-blank
  74.                                                 line on page */
  75.     short                offset;            /* offset in STR# resource of first
  76.                                                 non-blank line on page */
  77.     Boolean            header;            /* true if header on this page */
  78. } Break1Info;
  79.  
  80. static Break1Info        (**Breaks1)[];        /* handle to page break info */
  81.  
  82. /*    Item numbers of items in custom page setup dialog. */
  83.  
  84. #define    sepLineItem        1
  85. #define    fontListItem    2
  86. #define    sizeTEItem        3
  87. #define    sizeListItem    4
  88. #define    reverseItem        5
  89. #define    leftTEItem        6
  90. #define    rightTEItem        7
  91. #define    topTEItem        8
  92. #define    bottomTEItem    9
  93.  
  94. /*    Global variables for custom page setup dialog. */
  95.  
  96. static TPPrDlg             PrtStlDialog;        /* pointer to stream object for page setup */
  97. static TPPrDlg                PrtJobDialog;        /* pointer to stream object for printing */
  98. static short                 FirstItem;            /* our first item number - 1 */
  99. static rpp_PrtBlock        *PBlock;                /* pointer to rpp_PrtBlock param block */
  100. static ProcPtr                StdItemProc;        /* pointer to standard item proc */
  101. static ModalFilterProcPtr    StdFltrProc;    /* pointer to standard filter proc */
  102. static ListHandle            FontList;            /* handle to font list */    
  103. static ListHandle            SizeList;            /* handle to size list */
  104.  
  105. /*______________________________________________________________________
  106.  
  107.     GetLSep - Get Line Separation
  108.     
  109.     Entry:    fontNum = font number.
  110.                 fontSize = font size.
  111.     
  112.     Exit:        function result = line speparation.
  113. _____________________________________________________________________*/
  114.  
  115.  
  116. static short GetLSep (short fontNum, short fontSize)
  117.  
  118. {
  119.     FontInfo            fontInfo;        /* font info */
  120.     
  121.     TextFont(fontNum);
  122.     TextSize(fontSize);
  123.     TextFace(normal);
  124.     GetFontInfo(&fontInfo);
  125.     return fontInfo.ascent + fontInfo.descent + fontInfo.leading;
  126. }
  127.  
  128. /*______________________________________________________________________
  129.  
  130.     GetHH - Get Header Height
  131.     
  132.     Entry:    p = pointer to parameter block
  133.     
  134.     Exit:        function result = header height.
  135. _____________________________________________________________________*/
  136.  
  137.  
  138. static short GetHH (rpp_PrtBlock *p)
  139.  
  140. {
  141.     FontInfo            fontInfo;        /* font info */
  142.     
  143.     TextFont(p->titleFont);
  144.     TextSize(TitleSize);
  145.     TextFace(p->titleStyle);
  146.     GetFontInfo(&fontInfo);
  147.     return fontInfo.ascent + fontInfo.descent + 
  148.         p->titleSep * (**p->hPrint).prInfo.iVRes / 100;
  149. }
  150.  
  151. /*______________________________________________________________________
  152.  
  153.     CheckHeaderWidth - Check Page Header Width.
  154.     
  155.     Entry:    p = pointer to parameter block.
  156. _____________________________________________________________________*/
  157.  
  158.  
  159. static void CheckHeaderWidth (rpp_PrtBlock *p)
  160.  
  161. {
  162.     Str255        rhSide;                /* date, time, and page number */
  163.     
  164.     if (!p->header) return;
  165.     TextFont(p->titleFont);
  166.     TextSize(TitleSize);
  167.     TextFace(p->titleStyle);
  168.     utl_PlugParams((Str255 *)p->titleTmpl, &rhSide, &NowDate, &NowTime, (Str255 *)"\p999", nil);
  169.     if (StringWidth((StringPtr)(p->title)) + StringWidth((StringPtr)&rhSide) + 10 > PrintBoxWidth)
  170.         TruncateRight = true;
  171. }
  172.  
  173. /*______________________________________________________________________
  174.  
  175.     CheckCancel - Check for Cancel of Printing Operation.
  176.     
  177.     Exit:            function result = true if canceled, else false.
  178. _____________________________________________________________________*/
  179.  
  180.  
  181. static Boolean CheckCancel(void)
  182.  
  183. {
  184.     EventRecord        myEvent;                /* event record */
  185.     char                key;                    /* key pressed */
  186.     
  187.     if (utl_WaitNextEvent(everyEvent ^ diskMask, &myEvent, 0, nil)) {
  188.         switch (myEvent.what) {
  189.             case keyDown:
  190.                 key = myEvent.message & charCodeMask;
  191.                 if (((myEvent.modifiers & cmdKey) && key == '.') ||
  192.                     key == escapeKey) return true;
  193.                 break;
  194.             default:
  195.                 break;
  196.         };
  197.     };
  198.     return false;
  199. }
  200.  
  201. /*______________________________________________________________________
  202.  
  203.     Break0 - Compute Page Breaks for a Type 0 Report.
  204.     
  205.     Entry:    theList = handle to list record.
  206.                 p = pointer to parameter block.
  207.                 
  208.     Exit:        function result = true if canceled by user.
  209. _____________________________________________________________________*/
  210.  
  211.  
  212. static Boolean Break0 (ListHandle theList, rpp_PrtBlock *p)
  213.  
  214. {
  215.     GrafPtr            port;                /* current grafport */
  216.     short                oldFont;            /* saved font number */
  217.     short                oldFace;            /* saved font style */
  218.     short                oldSize;            /* saved font size */
  219.     long                lineNum;            /* line number of first line on cur page */
  220.     short                lastLine;        /* last line number in report + 1 */
  221.     short                pageNum;            /* current page number */
  222.     short                lineSep;            /* line separation */
  223.     short                height;            /* height of page */
  224.     long                linesPerPage;    /* number of lines per page */
  225.     Break0Info        breakInfo;        /* page break info for current page */
  226.     short                endPage;            /* last page number */
  227.     short                numLines;        /* number of lines left to check */
  228.     Cell                theCell;            /* list manager cell */
  229.     char                line[256];        /* line to be printed */
  230.     short                lineLen;            /* length of line */
  231.     Boolean            canceled;        /* true if canceled by user */
  232.     
  233.     /* Save font info. */
  234.     
  235.     GetPort(&port);
  236.     oldFont = port->txFont;
  237.     oldFace = port->txFace;
  238.     oldSize = port->txSize;    
  239.     
  240.     /* Check header width. */
  241.     
  242.     CheckHeaderWidth(p);
  243.  
  244.     /* Compute linesPerPage = number of report lines per page. */
  245.     
  246.     height = PrintBoxHeight;    
  247.     if (p->header) height -= GetHH(p);
  248.     lineSep = GetLSep(p->fontNum, p->fontSize);
  249.     linesPerPage = height/lineSep;
  250.     
  251.     /* Check to see if any lines are too wide. */
  252.     
  253.     lastLine = (**theList).dataBounds.bottom;
  254.     numLines = lastLine;
  255.     SetPt(&theCell, 0, 0);
  256.     canceled = false;
  257.     while (numLines--) {
  258.         if (canceled = CheckCancel()) break;
  259.         lineLen = 256;
  260.         LGetCell(line, &lineLen, theCell, theList);
  261.         if (TextWidth(line, 0, lineLen) > PrintBoxWidth) {
  262.             TruncateRight = true;
  263.             break;
  264.         };
  265.         theCell.v++;
  266.     };
  267.     
  268.     /* Restore font info. */
  269.     
  270.     TextFont(oldFont);
  271.     TextFace(oldFace);
  272.     TextSize(oldSize);
  273.     
  274.     /* Compute the PageBreaks array. */
  275.     
  276.     lineNum = (FirstPage-1)*linesPerPage;
  277.     if (lineNum >= lastLine) {
  278.         LastPage = FirstPage-1;
  279.         Breaks0 = (Break0Info(**)[])NewHandle(0);
  280.     } else {
  281.         endPage = FirstPage + (lastLine-lineNum-1)/linesPerPage;
  282.         if (endPage < LastPage) LastPage = endPage;
  283.         Breaks0 = 
  284.             (Break0Info(**)[])NewHandle(sizeof(Break0Info)*(LastPage-FirstPage+1));
  285.         for (pageNum = FirstPage; pageNum <= LastPage; pageNum++) {
  286.             breakInfo.firstLine = lineNum;
  287.             lineNum += linesPerPage;
  288.             breakInfo.numLines = (lineNum <= lastLine) ? linesPerPage :
  289.                 (lastLine - breakInfo.firstLine);
  290.             (**Breaks0)[pageNum-FirstPage] = breakInfo;
  291.         };
  292.     };
  293.     return canceled;
  294. };
  295.  
  296. /*______________________________________________________________________
  297.  
  298.     LoadStrings - Load STR# Resource.
  299.     
  300.     Entry:    theList = handle to list record.
  301.                 auxInx = index in aux array.
  302.                 
  303.     Exit:        theStrings = handle to loaded and locked STR# resource.
  304.                 endStrings = pointer to byte following STR# resource.
  305.                 endOfDoc = true if end of STR# resources.
  306. _____________________________________________________________________*/
  307.  
  308.  
  309. static void LoadStrings (ListHandle theList, short auxInx, 
  310.     Handle *theStrings, unsigned char **endStrings, Boolean *endOfDoc)
  311.  
  312. {
  313.     auxInfo            **aux;            /* handle to auxiliary info */
  314.     Handle            s;                    /* handle to STR# resource */
  315.  
  316.     aux = (auxInfo**)(**theList).userHandle;
  317.     if (!(s = (**aux).auxArray[auxInx])) {
  318.         *endOfDoc = true;
  319.         *theStrings = nil;
  320.         return;
  321.     };
  322.     if (!*s) LoadResource(s);
  323.     MoveHHi(s);
  324.     HLock(s);
  325.     *theStrings = s;
  326.     *endStrings = (unsigned char *)*s + GetHandleSize(s);
  327. }
  328.  
  329. /*______________________________________________________________________
  330.  
  331.     Wrap - Wrap Paragraph.
  332.     
  333.     Entry:    printing = true to print paragraph, false to just compute
  334.                     paragraph size.
  335.                 v = vertical position on page.
  336.                 fontNum = font number.
  337.                 fontSize = font size.
  338.                 fontStyle = font style.
  339.                 just = justification (docLeft, docCenter, or docRight).
  340.                 theLine = pointer to first line of paragraph.
  341.                 firstChar = pointer to first char of paragraph (following
  342.                     any escape sequences in first line).
  343.     
  344.     Exit:        allBlank = true if paragraph is all blanks.
  345.                 nLines = number of lines in paragraph.
  346.                 lastLine = pointer to last line in paragraph.
  347. _____________________________________________________________________*/
  348.  
  349.  
  350. static void Wrap (Boolean printing, short v, short fontNum, 
  351.     short fontSize, short fontStyle, short just, unsigned char *theLine, 
  352.     unsigned char *firstChar, Boolean *allBlank, short *nLines, 
  353.     unsigned char **lastLine)
  354.  
  355. {
  356.     char                    pl[200];            /* line to be printed */
  357.     short                    npl;                /* length of print line */
  358.     short                    n;                    /* number of lines */
  359.     short                    nbl;                /* num chars in blank run */
  360.     short                    xbl;                /* set to 1 for interpolated blank */
  361.     short                    nw;                /* number of words */
  362.     unsigned char        *q;                /* pointer into cur line */
  363.     unsigned char        *qend;            /* pointer to end+1 of cur line */
  364.     Boolean                eop;                /* true if end of paragraph */
  365.     Boolean                allb;                /* true if all blank paragraph */
  366.     short                    lineSep;            /* line separation */
  367.     FontInfo                fontInfo;        /* font info */
  368.     short                    w;                    /* actual width of printed line */
  369.     
  370.     /* Get font info and set proper font number, size, and style. */
  371.     
  372.     TextFont(fontNum);
  373.     TextSize(fontSize);
  374.     TextFace(normal);
  375.     GetFontInfo(&fontInfo);
  376.     TextFace(fontStyle);
  377.     
  378.     /* Initialize variables. */
  379.     
  380.     n = 1;
  381.     allb = true;
  382.     npl = 0;
  383.     q = firstChar;
  384.     qend = theLine + *theLine + 1;
  385.     eop = false;
  386.     lineSep = fontInfo.leading + fontInfo.ascent + fontInfo.descent;
  387.     if (printing) v += fontInfo.leading + fontInfo.ascent;
  388.     xbl = 0;
  389.     
  390.     /* Main loop.  Wrap the entire paragraph. */
  391.     
  392.     while (!eop) {
  393.     
  394.         /* Check to see if this is the last line in the paragraph.
  395.             If it is, back over the eop marker at the end of the line. */
  396.     
  397.         if (eop = (q < qend && *(qend-1) == docEop)) qend--;
  398.         
  399.         /* Break out blank runs and words from the line one at a time. */
  400.         
  401.         while (q < qend) {
  402.         
  403.             /* Get nbl = num blanks in next blank run. */
  404.             
  405.             nbl = xbl;
  406.             xbl = 0;
  407.             while (q < qend && *q == ' ') {
  408.                 q++;
  409.                 nbl++;
  410.             };
  411.             if (q == qend) break;
  412.             
  413.             /* Get nw = num chars in next word */
  414.             
  415.             allb = false;
  416.             nw = 0;
  417.             while (q < qend && *q != ' ') {
  418.                 q++;
  419.                 nw++;
  420.             };
  421.             
  422.             /* Append blanks and word to current line. */
  423.             
  424.             if (nbl) memset(pl+npl, ' ', nbl);
  425.             npl += nbl;
  426.             memcpy(pl+npl, q-nw, nw);
  427.             npl += nw;
  428.             
  429.             /* Check to see if it's time to wrap.  If it is, print the
  430.                 current line and start a new one.  Put the word we just
  431.                 broke out of the paragraph at the beginning of the next
  432.                 line. */
  433.             
  434.             w = TextWidth(pl, 0, npl);
  435.             if (w > PrintBoxWidth) {
  436.                 if (printing) {
  437.                     switch (just) {
  438.                         case docLeft:
  439.                             MoveTo(PrintBox.left, v);
  440.                             break;
  441.                         case docCenter:
  442.                             MoveTo(PrintBox.left + ((PrintBoxWidth-w)>>1), v);
  443.                             break;
  444.                         case docRight:
  445.                             MoveTo(PrintBox.right-w, v);
  446.                             break;
  447.                     };
  448.                     DrawText(pl, 0, npl-nw-nbl);
  449.                     v += lineSep;
  450.                 } else if (nw == npl) TruncateRight = true;
  451.                 n++;
  452.                 memcpy(pl, q-nw, nw);
  453.                 npl = nw;
  454.             };
  455.             
  456.         };
  457.         
  458.         /* Break if end of paragraph, else advance to next line.
  459.             Set xbl = 1 to force a blank to be interpolated at the 
  460.             beginning of the next line. */
  461.         
  462.         if (eop) break;
  463.         theLine += *theLine + 1;
  464.         q = theLine + 1;
  465.         qend = q + *theLine;
  466.         xbl = 1;
  467.         
  468.     };
  469.     
  470.     /* Print the last line. */
  471.     
  472.     if (printing) {
  473.         w = TextWidth(pl, 0, npl);
  474.         switch (just) {
  475.             case docLeft:
  476.                 MoveTo(PrintBox.left, v);
  477.                 break;
  478.             case docCenter:
  479.                 MoveTo(PrintBox.left + ((PrintBoxWidth-w)>>1), v);
  480.                 break;
  481.             case docRight:
  482.                 MoveTo(PrintBox.right-w, v);
  483.                 break;
  484.         };
  485.         DrawText(pl, 0, npl);
  486.     };
  487.     
  488.     /* Set exit params and return. */
  489.     
  490.     *allBlank = allb;
  491.     *nLines = n;
  492.     *lastLine = theLine;
  493. }
  494.  
  495. /*______________________________________________________________________
  496.  
  497.     Break1 - Compute Page Breaks for a Type 1 Report.
  498.     
  499.     Entry:    theList = handle to list record.
  500.                 p = pointer to parameter block.
  501.                 
  502.     Exit:        Break1 array records positions of page breaks.
  503.                 function result = true if canceled by command-period.
  504. _____________________________________________________________________*/
  505.  
  506.  
  507. static Boolean Break1 (ListHandle theList, rpp_PrtBlock *p)
  508.  
  509. {
  510.     GrafPtr            port;                    /* current grafport */
  511.     short                oldFont;                /* saved font number */
  512.     short                oldFace;                /* saved font style */
  513.     short                oldSize;                /* saved font size */
  514.     short                nalloc;                /* number of elements allocated in
  515.                                                     Breaks1 array */
  516.     Break1Info        breakInfo;            /* break info */                                                    
  517.     short                pageNum;                /* current page number */
  518.     short                v;                        /* current vert pos on page */
  519.     short                auxInx;                /* cur index in aux array */
  520.     Boolean            allBlank;            /* true if in initial blank portion
  521.                                                     of block */
  522.     Boolean            allBPar;                /* true if all blank paragrah */                                                    
  523.     short                hb;                    /*    height of initial blank portion
  524.                                                     of block */
  525.     short                hnb;                    /* height of non-blank portion of block */
  526.     Boolean            force;                /* true if page break forced by
  527.                                                     \page directive */
  528.     short                lineSep;                /* line separation for normal lines */
  529.     short                h;                        /* height of next section */
  530.     Boolean            header;                /* true if header on next page */
  531.     Boolean            endOfDoc;            /* true if end of doc */
  532.     short                headerHeight;        /* height of page header */    
  533.     Handle            theStrings;            /* handle to STR# resource */
  534.     unsigned char    *endStrings;        /* ptr to byte followng STR# rsrc */
  535.     unsigned char    *theLine;            /* pointer to cur line in STR# rsrc */
  536.     unsigned char    *q;                    /* pointer to cur pos in line */
  537.     unsigned char    *qEnd;                /* pointer to end of line */
  538.     Boolean            keepBlock;            /* true if \keep directive encountered */
  539.     Boolean            done;                    /* true when end of section found */
  540.     Boolean            paragraph;            /* true if start of paragraph */
  541.     short                lSep;                    /* size adjusted line separation */
  542.     short                newSize;                /* scaled font size */
  543.     Boolean            pict;                    /* true if picture */
  544.     short                picID;                /* pict id */
  545.     PicHandle        picHandle;            /* pict handle */
  546.     Rect                picRect;                /* pict frame rectangle */
  547.     short                style;                /* font style */
  548.     short                nLines;                /* num lines in paragraph */
  549.     short                cellHeight;            /* height of list manager cells */
  550.     Boolean            laser;                /* true if laserwriter */
  551.     Boolean            canceled;            /* true if canceled */
  552.     Boolean            tcon;                    /* true if tcon escape seq encountered */
  553.     short                tconMaxT;            /* width of widest tcon title */
  554.     short                tconMaxN;            /* width of widest tcon page number */
  555.     char                *tconPtr;            /* ptr to cur pos in TCON rsrc */
  556.     short                tconCount;            /* num TCON entries left to process */
  557.     Handle            tconHandle;            /* handle to TCON rsrc */
  558.     short                tconTWidth;            /* width of title */
  559.     unsigned char    *tconStart;            /* ptr to first non-blank char of tcon
  560.                                                     title */
  561.     short                tconNBl;                /* number of leading blanks in tcon
  562.                                                     title */
  563.     
  564.     /* Save font number, style, and size. */
  565.     
  566.     GetPort(&port);
  567.     oldFont = port->txFont;
  568.     oldFace = port->txFace;
  569.     oldSize = port->txSize;
  570.     
  571.     /* Check header width. */
  572.     
  573.     CheckHeaderWidth(p);
  574.  
  575.     /* Initialize variables. */
  576.     
  577.     pageNum = 0;
  578.     v = PrintBox.bottom + 1;
  579.     auxInx = 0;
  580.     lineSep = GetLSep(p->fontNum, p->fontSize);
  581.     headerHeight = GetHH(p);
  582.     cellHeight = (**theList).cellSize.v;
  583.     endOfDoc = false;
  584.     laser = utl_IsLaser(p->hPrint);
  585.     canceled = false;
  586.     tcon = false;
  587.     theStrings = nil;
  588.     
  589.     /* Load the first STR# resource and lock it. */
  590.     
  591.     LoadStrings(theList, auxInx, &theStrings, &endStrings, &endOfDoc);
  592.     theLine = (unsigned char *)*theStrings+2;
  593.     
  594.     /* Allocate 10 initial elements in Breaks1 array. */
  595.     
  596.     Breaks1 = (Break1Info(**)[])NewHandle(10*sizeof(Break1Info));
  597.     nalloc = 10;
  598.     
  599.     /* Main loop. Paginate the entire document. */
  600.     
  601.     while (true) {
  602.     
  603.         /* Check for command-period */
  604.         
  605.         if (canceled = CheckCancel()) break;
  606.     
  607.         hb = hnb = 0;
  608.         force = false;
  609.         keepBlock = false;
  610.         breakInfo.auxInxB = breakInfo.auxInx = auxInx;
  611.         breakInfo.offsetB = breakInfo.offset = theLine - (unsigned char *)*theStrings;
  612.         
  613.         /* Find next "block".  A block is defined to be a possibly empty
  614.             sequence of blank lines, followed by a keep block, a paragraph,
  615.             or a picture.
  616.             
  617.             Our goal is to compute the following:
  618.             
  619.             hb = height of initial blank portion of block.
  620.             hnb = height of non-blank portion of block.
  621.             theLine = pointer to line following block. 
  622.             breakInfo.auxInx = index in aux array of beginning of non-blank
  623.                 portion of block.
  624.             breakInfo.offset = offset in STR# of beginning of non-blank
  625.                 portion of block. */
  626.         
  627.         while (true) {
  628.         
  629.             h = 0;
  630.             allBlank = true;
  631.             done = false;
  632.             
  633.             /* Find next "section".  A section is defined to be an empty
  634.                 line, a keep block, a paragraph, or a picture.
  635.                 
  636.                 Our goal is to compute the following:
  637.                 
  638.                 h = height of section.
  639.                 theLine = pointer to line following section.
  640.                 force = true if \page directive encountered.
  641.                 allBlank = true if blank line. */
  642.             
  643.             while (!done) {
  644.                 
  645.                 lSep = lineSep;
  646.                 q = theLine+1;
  647.                 qEnd = q + *theLine;
  648.                 paragraph = true;
  649.                 pict = false;
  650.                 style = normal;
  651.                 newSize = p->fontSize;
  652.                 
  653.                 /* Crack escape sequences. */
  654.                 
  655.                 while (q < qEnd && *q < 31) {
  656.                     switch (*q) {
  657.                         case docStyle:
  658.                             style = *(q+2);
  659.                             break;
  660.                         case docSize:
  661.                             newSize = utl_ScaleFontSize(p->fontNum, p->fontSize,
  662.                                 *(q+2)<<8 | *(q+3), laser);
  663.                             lSep = GetLSep(p->fontNum, newSize);
  664.                             break;
  665.                         case docOnly:
  666.                             paragraph = *(q+2) & docPrint;
  667.                             break;
  668.                         case docPict:
  669.                             pict = true;
  670.                             picID = *(q+2)<<8 | *(q+3);
  671.                             paragraph = false;
  672.                             break;
  673.                         case docPage:
  674.                             force = true;
  675.                             header = !*(q+2);
  676.                             paragraph = false;
  677.                             break;
  678.                         case docKeep:
  679.                             keepBlock = true;
  680.                             paragraph = false;
  681.                             break;
  682.                         case docEndKeep:
  683.                             done = true;
  684.                             paragraph = false;
  685.                             break;
  686.                         case docITcon:
  687.                             h += lineSep;
  688.                             allBlank = false;
  689.                             done = true;
  690.                             paragraph = false;
  691.                             tcon = true;
  692.                             break;
  693.                     };
  694.                     if (!paragraph) break;
  695.                     q += *(q+1);
  696.                 };
  697.                 
  698.                 /* Rewrap paragraph. */
  699.                 
  700.                 if (paragraph) {
  701.                     Wrap(false, 0, p->fontNum, newSize, style, docLeft, theLine,
  702.                         q, &allBPar, &nLines, &theLine);
  703.                     allBlank &= allBPar;
  704.                     h += nLines * lSep;
  705.                     done = !keepBlock;
  706.                 };
  707.                 
  708.                 if (pict) {
  709.                 
  710.                     /* For a picture, count the bands and compute h = the picture
  711.                         height. */
  712.                         
  713.                     while (true) {
  714.                         h += cellHeight;
  715.                         theLine += *theLine + 1;
  716.                         q = theLine + 1;
  717.                         qEnd = q + *theLine;
  718.                         pict = false;
  719.                         while (q < qEnd && *q < 31) {
  720.                             if (*q == docPict) {
  721.                                 pict = true;
  722.                                 break;
  723.                             };
  724.                             q += *(q+1);
  725.                         };
  726.                         if (!pict) break;
  727.                     };
  728.                     allBlank = false;
  729.                     done = !keepBlock;
  730.                     
  731.                     /* Check to see if picture is too wide for specified margins. */
  732.                     
  733.                     picHandle = GetPicture(picID);
  734.                     picRect = (**picHandle).picFrame;
  735.                     if ((picRect.right - picRect.left) > PrintBoxWidth) TruncateRight = true;
  736.                     
  737.                 } else {
  738.                 
  739.                     /* If not a picture, advance to next line. */
  740.                 
  741.                     theLine += *theLine + 1;
  742.                     
  743.                 };
  744.                 
  745.                 /* Advance to next STR# resource if necessary. */
  746.                 
  747.                 if (theLine >= endStrings) {
  748.                     HUnlock(theStrings);
  749.                     auxInx++;
  750.                     LoadStrings(theList, auxInx, &theStrings, &endStrings, 
  751.                         &endOfDoc);
  752.                     if (endOfDoc) break;
  753.                     theLine = (unsigned char *)*theStrings + 2;
  754.                 };
  755.                 
  756.             };
  757.             
  758.             /* At this point we have found the next section, and h = the
  759.                 height of the section. */
  760.             
  761.             if (allBlank) {
  762.             
  763.                 /* Accumulate height of blank line and loop for next section. */
  764.             
  765.                 hb += h;
  766.                 breakInfo.auxInx = auxInx;
  767.                 breakInfo.offset = theLine - (unsigned char *)*theStrings;
  768.                 if (endOfDoc) break;
  769.                 
  770.             } else {
  771.             
  772.                 /* Not blank line - set height of keep block, picture, or
  773.                     paragraph and break out of the section loop. */
  774.             
  775.                 hnb = h;
  776.                 break;
  777.                 
  778.             };
  779.             
  780.         };
  781.         
  782.         /* At this point we have found the next block, and we have: 
  783.             hb = height of blank portion at beginning of block.
  784.             hnb = height of non-blank portion (keep block, pict, or paragraph).
  785.         
  786.             Check to see if there's enough room on the page for this block. */
  787.         
  788.         if (v+hb+hnb > PrintBox.bottom || force) {
  789.             
  790.             /* Not enough room for block or \page encountered - do a page break.  
  791.                 Don't put blank lines at the top of the page. */
  792.         
  793.             pageNum++;
  794.             breakInfo.header = header;
  795.             if (pageNum >= nalloc) {
  796.                 SetHandleSize((Handle)Breaks1, 
  797.                     GetHandleSize((Handle)Breaks1) + 10*sizeof(Break1Info));
  798.                 nalloc += 10;
  799.             };
  800.             (**Breaks1)[pageNum] = breakInfo;
  801.             v = PrintBox.top;
  802.             if (header) v += headerHeight;
  803.             v += hnb;
  804.             if (v > PrintBox.bottom) TruncateBottom = true;
  805.             
  806.         } else {
  807.         
  808.             /* Enough room for block - advance position on page. */
  809.         
  810.             v += hb + hnb;
  811.             
  812.         };
  813.         
  814.         if (endOfDoc) break;
  815.         
  816.     };
  817.     
  818.     /* Set LastPage and adjust final size of Break1 array. */
  819.     
  820.     if (pageNum < LastPage) LastPage = pageNum;
  821.     if (LastPage < FirstPage) LastPage = FirstPage-1;
  822.     SetHandleSize((Handle)Breaks1, (pageNum+1)*sizeof(Break1Info));
  823.     
  824.     /* If a tcon escape sequence was encountered, check to see if the tcon
  825.         entries are wider than the print box width. */
  826.         
  827.     if (tcon && !canceled) {
  828.         TextFont(p->fontNum);
  829.         TextSize(p->fontSize);
  830.         TextFace(normal);
  831.         tconHandle = GetResource('TCON', p->tabConID);
  832.         if (!*tconHandle) LoadResource(tconHandle);
  833.         MoveHHi(tconHandle);
  834.         HLock(tconHandle);
  835.         tconCount = **(short**)tconHandle;
  836.         tconPtr = *tconHandle+2;
  837.         tconMaxT = 0;
  838.         while (tconCount--) {
  839.             if (*(tconPtr+2) & docPrint) {
  840.                 tconStart = (unsigned char *)tconPtr+4;
  841.                 while (*tconStart == ' ') tconStart++;
  842.                 tconNBl = tconStart - (unsigned char *)tconPtr - 4;
  843.                 tconTWidth = ((tconNBl*p->fontSize)>>1) +
  844.                     TextWidth((Ptr)tconStart, 0, *(tconPtr+3)-tconNBl);
  845.                 if (tconTWidth > tconMaxT) tconMaxT = tconTWidth;
  846.             };
  847.             tconPtr += *(tconPtr+3) + 4;
  848.             if ((long)tconPtr & 1) tconPtr++;
  849.         };
  850.         tconMaxN = StringWidth((StringPtr)"\p999");
  851.         if (tconMaxT+tconMaxN+10 > PrintBoxWidth) TruncateRight = true;
  852.         HUnlock(tconHandle);                    
  853.     };
  854.     
  855.     if (theStrings) HUnlock(theStrings);
  856.     
  857.     /* Restore font number, style, and size. */
  858.     
  859.     TextFont(oldFont);
  860.     TextFace(oldFace);
  861.     TextSize(oldSize);
  862.     
  863.     return canceled;
  864. }
  865.  
  866. /*______________________________________________________________________
  867.  
  868.     PrintHeader - Print Page Header.
  869.     
  870.     Entry:    p = pointer to parameter block.
  871.                 pageNum = page number to print.
  872. _____________________________________________________________________*/
  873.  
  874.  
  875. static void PrintHeader (rpp_PrtBlock *p, short pageNum)
  876.  
  877. {
  878.     FontInfo        fontInfo;            /* font info */
  879.     short            v;                        /* vert coord of header base line */
  880.     Str255        pNum;                    /* page number */
  881.     Str255        rhSide;                /* date, time, and page number */
  882.     
  883.     TextFont(p->titleFont);
  884.     TextSize(TitleSize);
  885.     TextFace(p->titleStyle);
  886.     GetFontInfo(&fontInfo);
  887.     v = PrintBox.top + fontInfo.ascent;
  888.     MoveTo(PrintBox.left, v);
  889.     DrawString((StringPtr)p->title);
  890.     NumToString(pageNum, pNum);
  891.     utl_PlugParams((Str255 *)p->titleTmpl, &rhSide, &NowDate, &NowTime, &pNum, nil);
  892.     MoveTo(PrintBox.right - StringWidth(rhSide), v);
  893.     DrawString(rhSide);
  894. }
  895.  
  896. /*______________________________________________________________________
  897.  
  898.     Print0 - Print one Page from a Type 0 Report.
  899.     
  900.     Entry:    theList = handle to list record.
  901.                 p = pointer to parameter block.
  902.                 pageNum = page number to print.
  903. _____________________________________________________________________*/
  904.  
  905.  
  906. static void Print0 (ListHandle theList, rpp_PrtBlock *p, short pageNum)
  907.  
  908. {
  909.     short                v;                /* current vertical coord on page */
  910.     FontInfo            fontInfo;    /* font info */
  911.     short                lineSep;        /* line separation */
  912.     Cell                theCell;        /* list manager cell */
  913.     char                line[256];    /* line to be printed */
  914.     short                lineLen;        /* length of line */
  915.     Break0Info        breakInfo;    /* page break info */
  916.  
  917.     v = PrintBox.top;
  918.     
  919.     /* Print the page header, if requested. */
  920.     
  921.     if (p->header) {
  922.         PrintHeader(p, pageNum);
  923.         v += GetHH(p);
  924.     };
  925.     if (CheckCancel()) return;
  926.     
  927.     /* Print the page body. */
  928.     
  929.     TextFont(p->fontNum);
  930.     TextSize(p->fontSize);
  931.     TextFace(normal);
  932.     GetFontInfo(&fontInfo);
  933.     lineSep = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
  934.     breakInfo = (**Breaks0)[pageNum-FirstPage];
  935.     SetPt(&theCell, 0, breakInfo.firstLine);
  936.     while (breakInfo.numLines--) {
  937.         if (CheckCancel()) return;
  938.         v += lineSep;
  939.         lineLen = 256;
  940.         LGetCell(line, &lineLen, theCell, theList);
  941.         MoveTo(PrintBox.left, v);
  942.         DrawText((Ptr)&line, 0, lineLen);
  943.         theCell.v++;
  944.     };
  945.     return;
  946. }
  947.  
  948. /*______________________________________________________________________
  949.  
  950.     Print1 - Print one Page from a Type 1 Report..
  951.     
  952.     Entry:    theList = handle to list record.
  953.                 p = pointer to parameter block.
  954.                 pageNum = page number to print.
  955. _____________________________________________________________________*/
  956.  
  957.  
  958. static void Print1 (ListHandle theList, rpp_PrtBlock *p, short pageNum)
  959.  
  960. {
  961.     short                v;                    /* current vertical coord on page */
  962.     Break1Info        breakInfo;        /* page break info */
  963.     short                auxInx;            /* cur index in aux array */
  964.     short                offset;            /* cur offset in aux array */
  965.     short                endAuxInx;        /* ending index in aux array */
  966.     short                endOffset;        /* ending offset in STR# rsrc */
  967.     FontInfo            fontInfo;        /* font info */
  968.     short                lineSep;            /* line separation */
  969.     Handle            theStrings;        /* handle to STR# rsrc */
  970.     unsigned char    *endStrings;    /* ptr to byte following STR# rsrc */
  971.     unsigned char    *theLine;        /* ptr to cur line in STR# rsrc */
  972.     unsigned char    *q;                /* ptr to cur pos in line */
  973.     unsigned char    *qEnd;            /* ptr to end of line */
  974.     Boolean            endOfDoc;        /* true if end of doc */
  975.     Boolean            endOfPage;        /* true if end of page */
  976.     Boolean            allBlank;        /* true if all blank paragraph (not used) */
  977.     Boolean            paragraph;        /* true if start of paragraph */
  978.     Boolean            pict;                /* true if start of picture */
  979.     short                lSep;                /* size adjusted line separation */
  980.     short                newSize;            /* scaled font size */
  981.     short                style;            /* font style */
  982.     short                escJust;            /* true if just escape sequence */
  983.     short                just;                /* justification */
  984.     short                nLines;            /* num lines in paragraph */
  985.     short                nBands;            /* num bands in picture */
  986.     short                picID;            /* resource id of picture */
  987.     PicHandle        picHandle;        /* handle to picture */
  988.     Rect                picRect;            /* picture dest rect */
  989.     short                picLeft;            /* left coord of picture */
  990.     short                tconMaxT;        /* width of widest tcon title */
  991.     char                *tconPtr;        /* ptr to cur pos in TCON rsrc */
  992.     short                tconCount;        /* num TCON entries left to process */
  993.     Handle            tconHandle;        /* handle to TCON rsrc */
  994.     Break1Info        *tconBPtr;        /* ptr to cur pos in Breaks1 array */
  995.     Break1Info        *tconBEnd;        /* ptr to end of Breaks1 array */
  996.     short                tconPass;        /* pass number - 0 or 1 */
  997.     short                tconLine;        /* line number */
  998.     unsigned char    *tconData;        /* pointer to cell data */
  999.     short                tconAuxInx;        /* index in aux array */
  1000.     short                tconOffset;        /* offset in STR# resource */
  1001.     short                tconPageNum;    /* page number */
  1002.     Str255            tconPNum;        /* page number as a string */
  1003.     short                tconTWidth;        /* width of title */
  1004.     short                tconNWidth;        /* width of page numbers */
  1005.     short                tconHPeriod;    /* hor coord of dot */
  1006.     short                tconPerSep;        /* tcon dot separation */
  1007.     unsigned char    *tconStart;        /* ptr to first non-blank char of tcon
  1008.                                                 title */
  1009.     short                tconNBl;            /* number of leading blanks in tcon
  1010.                                                 title */
  1011.     unsigned char    tconLineNum;    /* tcon line number to be printed */
  1012.     Boolean            laser;            /* true if laserwriter */
  1013.     
  1014.     /* The following local variables are declared static so that they will survive
  1015.         across calls.  The variables are recomputed only once per print job. */
  1016.         
  1017.     static short    tconLeft;            /* left margin for tcon */
  1018.     static short    tconRight;            /* right margin for tcon */
  1019.     static short    tconMaxN;            /* width of widest tcon page number */
  1020.  
  1021.     v = PrintBox.top;
  1022.     laser = utl_IsLaser(p->hPrint);
  1023.     theStrings = nil;
  1024.     
  1025.     /* Get page break info for this page. */
  1026.     
  1027.     breakInfo = (**Breaks1)[pageNum];
  1028.     auxInx = breakInfo.auxInx;
  1029.     offset = breakInfo.offset;
  1030.     
  1031.     /* Get info about where this page ends:
  1032.         endAuxInx = index in aux array where page ends.
  1033.         endOffset = offset in STR# rsrc where page ends. */
  1034.         
  1035.     if ((pageNum+1)*sizeof(Break1Info) < GetHandleSize((Handle)Breaks1)) {
  1036.         endAuxInx = (**Breaks1)[pageNum+1].auxInx;
  1037.         endOffset = (**Breaks1)[pageNum+1].offset;
  1038.     } else {
  1039.         endAuxInx = endOffset = 0x7fff;
  1040.     };
  1041.     
  1042.     /* Print the page header, if any. */
  1043.     
  1044.     if (breakInfo.header && p->header) {
  1045.         PrintHeader(p, pageNum);
  1046.         v += GetHH(p);
  1047.     };
  1048.     if (CheckCancel()) return;
  1049.     
  1050.     /* Set the font number, size, and style, and get font info. */
  1051.     
  1052.     TextFont(p->fontNum);
  1053.     TextSize(p->fontSize);
  1054.     TextFace(normal);
  1055.     GetFontInfo(&fontInfo);
  1056.     lineSep = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
  1057.     
  1058.     /* Load the first STR# resource and lock it.  Initialize theLine
  1059.         to point to the first line to be printed. */
  1060.     
  1061.     endOfDoc = false;
  1062.     LoadStrings(theList, auxInx, &theStrings, &endStrings, &endOfDoc);
  1063.     theLine = (unsigned char *)*theStrings + offset;
  1064.     
  1065.     /* Initialize other variables. */
  1066.     
  1067.     endOfPage = endOfDoc;
  1068.     
  1069.     /* Main loop.  Print the page. */
  1070.     
  1071.     while (!endOfPage) {
  1072.     
  1073.         if (CheckCancel()) break;
  1074.         lSep = lineSep;
  1075.         q = theLine+1;
  1076.         qEnd = q + *theLine;
  1077.         paragraph = true;
  1078.         pict = false;
  1079.         style = normal;
  1080.         newSize = p->fontSize;
  1081.         escJust = false;
  1082.         
  1083.         /* Crack escape sequences. */
  1084.         
  1085.         while (q < qEnd && *q < 31) {
  1086.             switch (*q) {
  1087.                 case docStyle:
  1088.                     style = *(q+2);
  1089.                     break;
  1090.                 case docSize:
  1091.                     newSize = utl_ScaleFontSize(p->fontNum, p->fontSize,
  1092.                         *(q+2)<<8 | *(q+3), laser);
  1093.                     lSep = GetLSep(p->fontNum, newSize);
  1094.                     break;
  1095.                 case docJust:
  1096.                     escJust = true;
  1097.                     just = *(q+2);
  1098.                     break;
  1099.                 case docOnly:
  1100.                     paragraph = *(q+2) & docPrint;
  1101.                     break;
  1102.                 case docPict:
  1103.                     pict = true;
  1104.                     picID = *(q+2)<<8 | *(q+3);
  1105.                     paragraph = false;
  1106.                     break;
  1107.                 case docPage:
  1108.                 case docKeep:
  1109.                 case docEndKeep:
  1110.                     paragraph = false;
  1111.                     break;
  1112.                 case docITcon:
  1113.                     TextFont(p->fontNum);
  1114.                     TextSize(p->fontSize);
  1115.                     TextFace(normal);
  1116.                     tconHandle = GetResource('TCON', p->tabConID);
  1117.                     if (!*tconHandle) LoadResource(tconHandle);
  1118.                     MoveHHi(tconHandle);
  1119.                     HLock(tconHandle);
  1120.                     for (tconPass = TconCompute; tconPass < 2; tconPass++) {
  1121.                         tconLineNum = *(q+2);
  1122.                         tconCount = **(short**)tconHandle;
  1123.                         tconPtr = *tconHandle+2;
  1124.                         if (!tconPass) tconMaxT = tconMaxN = 0;
  1125.                         while (tconCount--) {
  1126.                             if (CheckCancel()) return;
  1127.                             if (*(tconPtr+2) & docPrint) {
  1128.                                 if (!tconPass || !tconLineNum) {
  1129.                                     tconLine = *(short*)tconPtr;
  1130.                                     tconData = (unsigned char *)*(**theList).cells + 
  1131.                                         (**theList).cellArray[tconLine];
  1132.                                     tconAuxInx = *tconData;
  1133.                                     tconOffset = *(tconData+1)<<8 | *(tconData+2);
  1134.                                     tconBPtr = (Break1Info*)*Breaks1;
  1135.                                     tconBEnd = (Break1Info*)((char*)tconBPtr + 
  1136.                                         GetHandleSize((Handle)Breaks1));
  1137.                                     tconBPtr++;
  1138.                                     tconPageNum = 0;
  1139.                                     while (tconBPtr < tconBEnd) {
  1140.                                         if (tconAuxInx < tconBPtr->auxInxB) break;
  1141.                                         if (tconAuxInx == tconBPtr->auxInxB &&
  1142.                                             tconOffset < tconBPtr->offsetB) break;
  1143.                                         tconBPtr++;
  1144.                                         tconPageNum++;
  1145.                                     };
  1146.                                     tconStart = (unsigned char *)tconPtr+4;
  1147.                                     while (*tconStart == ' ') tconStart++;
  1148.                                     tconNBl = tconStart - (unsigned char *)tconPtr - 4;
  1149.                                     tconTWidth = ((tconNBl*p->fontSize)>>1) +
  1150.                                         TextWidth((Ptr)tconStart, 0, *(tconPtr+3)-tconNBl);
  1151.                                     NumToString(tconPageNum, tconPNum);
  1152.                                     tconNWidth = StringWidth(tconPNum);
  1153.                                     if (!tconPass) {
  1154.                                         if (tconTWidth > tconMaxT) tconMaxT = tconTWidth;
  1155.                                         if (tconNWidth > tconMaxN) tconMaxN = tconNWidth;
  1156.                                     } else {
  1157.                                         v += lineSep;
  1158.                                         MoveTo(tconLeft + ((tconNBl*p->fontSize)>>1), v);
  1159.                                         DrawText((Ptr)tconStart, 0, *(tconPtr+3)-tconNBl);
  1160.                                         MoveTo(tconRight-tconNWidth, v);
  1161.                                         DrawString(tconPNum);
  1162.                                         tconPerSep = (p->fontSize - 4) >> 1;
  1163.                                         if (tconPerSep < 3) tconPerSep = 3;
  1164.                                         tconHPeriod = tconRight-tconMaxN-(tconPerSep<<1);
  1165.                                         while (tconHPeriod > tconLeft+tconTWidth+tconPerSep) {
  1166.                                             MoveTo(tconHPeriod, v);
  1167.                                             DrawChar('.');
  1168.                                             tconHPeriod -= tconPerSep;
  1169.                                         };
  1170.                                         break;
  1171.                                     };
  1172.                                 };
  1173.                                 tconLineNum--;
  1174.                             };
  1175.                             tconPtr += *(tconPtr+3) + 4;
  1176.                             if ((long)tconPtr & 1) tconPtr++;
  1177.                         };
  1178.                         if (!tconPass) {
  1179.                             if (tconMaxT+tconMaxN+72 > PrintBoxWidth) {
  1180.                                 tconLeft = PrintBox.left;
  1181.                                 tconRight = PrintBox.right;
  1182.                             } else {
  1183.                                 tconLeft = PrintBox.left + 
  1184.                                     ((PrintBoxWidth - (tconMaxT+tconMaxN+72))>>1);
  1185.                                 tconRight = tconLeft + tconMaxT + tconMaxN + 72;
  1186.                             };
  1187.                             TconCompute = 1;
  1188.                         };
  1189.                     };
  1190.                     HUnlock(tconHandle);                    
  1191.                     paragraph = false;
  1192.                     break;
  1193.             };
  1194.             if (!paragraph) break;
  1195.             q += *(q+1);
  1196.         };
  1197.         
  1198.         /* Rewrap paragraph. */
  1199.         
  1200.         if (paragraph) {
  1201.             if (!escJust) just = docLeft;
  1202.             Wrap(true, v, p->fontNum, newSize, style, just, theLine,
  1203.                 q, &allBlank, &nLines, &theLine);
  1204.             v += nLines * lSep;
  1205.         };
  1206.         
  1207.         if (pict) {
  1208.         
  1209.             /* Draw picture. */
  1210.         
  1211.             nBands = 0;
  1212.             while (true) {
  1213.                 nBands++;
  1214.                 theLine += *theLine + 1;
  1215.                 q = theLine + 1;
  1216.                 qEnd = q + *theLine;
  1217.                 pict = false;
  1218.                 while (q < qEnd && *q < 31) {
  1219.                     if (*q == docPict) {
  1220.                         pict = true;
  1221.                         break;
  1222.                     };
  1223.                     q += *(q+1);
  1224.                 };
  1225.                 if (!pict) break;
  1226.             };
  1227.             picHandle = GetPicture(picID);
  1228.             picRect = (**picHandle).picFrame;
  1229.             if (!escJust) just = docCenter;
  1230.             switch (just) {
  1231.                 case docLeft:
  1232.                     picLeft = PrintBox.left;
  1233.                     break;
  1234.                 case docCenter:
  1235.                     picLeft = PrintBox.left + ((PrintBoxWidth -
  1236.                         (picRect.right-picRect.left))>>1);
  1237.                     break;
  1238.                 case docRight:
  1239.                     picLeft = PrintBox.right - (picRect.right-picRect.left);
  1240.                     break;
  1241.             };
  1242.             OffsetRect(&picRect, picLeft-picRect.left, v-picRect.top);
  1243.             HLock((Handle)picHandle);
  1244.             DrawPicture(picHandle, &picRect);
  1245.             HUnlock((Handle)picHandle);
  1246.             v += nBands * (**theList).cellSize.v;
  1247.                     
  1248.         } else {
  1249.         
  1250.             /* If not a picture, advance to next line. */
  1251.         
  1252.             theLine += *theLine + 1;
  1253.             
  1254.         };
  1255.         
  1256.         /* Advance to next STR# resource if necessary. */
  1257.         
  1258.         if (theLine >= endStrings) {
  1259.             HUnlock(theStrings);
  1260.             auxInx++;
  1261.             LoadStrings(theList, auxInx, &theStrings, &endStrings, 
  1262.                 &endOfDoc);
  1263.             if (endOfDoc) break;
  1264.             theLine = (unsigned char *)*theStrings + 2;
  1265.         };
  1266.         
  1267.         /* Check for end of page. */
  1268.         
  1269.         endOfPage = auxInx >= endAuxInx && 
  1270.             (theLine - (unsigned char *)*theStrings) >= endOffset;
  1271.         
  1272.     };
  1273.     
  1274.     if (theStrings) HUnlock(theStrings);
  1275. }
  1276.  
  1277. /*______________________________________________________________________
  1278.  
  1279.     CalcPrintBox - Calculate Printing Rectangle
  1280.     
  1281.     Entry:    hPrint = handle to print record.
  1282.                 leftMargin = left margin in 1/100 inch.
  1283.                 rightMargin = right margin in 1/100 inch.
  1284.                 topMargin = top margin in 1/100 inch.
  1285.                 botMargin = bot margin in 1/100 inch.
  1286.                 
  1287.     Exit:        global variable PrintBox = printing rectangle.
  1288. _____________________________________________________________________*/
  1289.  
  1290.  
  1291. static void CalcPrintBox (THPrint hPrint, short leftMargin, 
  1292.     short rightMargin, short topMargin, short botMargin)
  1293.  
  1294. {
  1295.     Rect                rPaper;                /* paper rect */
  1296.     Rect                rPage;                /* page rect */
  1297.     short                iVRes;                /* vert printer resolution */
  1298.     short                iHRes;                /* horiz printer resolution */
  1299.     
  1300.     rPaper = (**hPrint).rPaper;
  1301.     rPage = (**hPrint).prInfo.rPage;
  1302.     iVRes = (**hPrint).prInfo.iVRes;
  1303.     iHRes = (**hPrint).prInfo.iHRes;
  1304.     PrintBox.left = rPaper.left + leftMargin*iHRes/100;
  1305.     if (PrintBox.left < 0) PrintBox.left = 0;
  1306.     PrintBox.right = rPaper.right - rightMargin*iHRes/100;
  1307.     if (PrintBox.right > rPage.right) PrintBox.right = rPage.right;
  1308.     PrintBox.top = rPaper.top + topMargin*iVRes/100;
  1309.     if (PrintBox.top < 0) PrintBox.top = 0;
  1310.     PrintBox.bottom = rPaper.bottom - botMargin*iVRes/100;
  1311.     if (PrintBox.bottom > rPage.bottom) PrintBox.bottom = rPage.bottom;
  1312.     PrintBoxHeight = PrintBox.bottom - PrintBox.top;
  1313.     PrintBoxWidth = PrintBox.right - PrintBox.left;
  1314. }
  1315.  
  1316. /*______________________________________________________________________
  1317.  
  1318.     MyJobDlgInit - Initialize custom printing dialog.
  1319.     
  1320.     Entry:    hPrint = handle to print record.
  1321.     
  1322.     Exit:        function result = pointer to print dialog stream object.
  1323. _____________________________________________________________________*/
  1324.  
  1325.  
  1326. static pascal TPPrDlg MyJobDlgInit (THPrint hPrint)
  1327.  
  1328. {
  1329.  
  1330.     DialogPtr        theDialog;        /* pointer to dialog */
  1331.     Rect                dlogRect;        /* dialog rectangle */
  1332.     
  1333.     theDialog = (DialogPtr)PrtJobDialog;
  1334.     
  1335.     /* Center the dialog. */
  1336.     
  1337.     dlogRect = theDialog->portRect;
  1338.     utl_CenterDlogRect(&dlogRect, PBlock->menuPick);
  1339.     MoveWindow(theDialog, dlogRect.left, dlogRect.top, false);
  1340.     
  1341.     return PrtJobDialog;
  1342. };
  1343.  
  1344. /*______________________________________________________________________
  1345.  
  1346.     rpp_Print - Print a Report.
  1347.     
  1348.     Entry:    repHandle = handle to report record.
  1349.                 printOne = true to bypass print job dialog.
  1350.                 p = pointer to parameter block, with fields set as follows:
  1351.     
  1352.                 hPrint = handle to print record.
  1353.                 fontNum = font number.
  1354.                 fontSize = font size.
  1355.                 topMargin = top page margin, in 1/100 inch.
  1356.                 botMargin = bottom page margin, in 1/100 inch.
  1357.                 leftMargin = left page margin, in 1/100 inch.
  1358.                 rightMargin = right page margin, in 1/100 inch.
  1359.                 reverseOrder = true to print pages in reverse order.
  1360.                 header = true to print page headers.
  1361.                 title = ptr to header title.  If header=true it this
  1362.                     string is printed at the top of each page left-justified.
  1363.                 titleSep = vertical separation between page header and 
  1364.                     first line of text, in 1/100 inch.
  1365.                 titleFont = font number for headers.
  1366.                 titleStyle = font style for headers.
  1367.                 titleSize = font size scaling factor for headers.
  1368.                 titleTmpl = ptr to template for header date, time, and page number.
  1369.                     e.g., "^0  ^1  page ^2".  The place-holders ^0, ^1, and ^2
  1370.                     are replaced by the current date, time, and page number.
  1371.                     This string is drawn right-justified at the top of each page,
  1372.                     if header=true.
  1373.                 docName = ptr to document name for printing in progress
  1374.                     dialog.
  1375.                 dlogID = resource id of printing dialog.  The place-holder
  1376.                     ^0 is replaced by the document name.
  1377.                 tabConID = TCON resource id, for type 1 reports only.
  1378.                 emptyPageRangeID = no pages in page range alert.
  1379.                 truncateRightID = resource id of page box too narrow alert.
  1380.                 truncateBottomID = resource id of page box too short alert.
  1381.                 boxTooSmallID = resource id of page box too small alert.
  1382.                 menuPick = true if Print command was via menu pick, 
  1383.                     false if command key used.
  1384.                 updateAll = pointer to function to handle all pending update
  1385.                     events, or nil if none. The function is called after the
  1386.                     job dialog is dismissed, and before the printing in progress
  1387.                     dialog is presented.
  1388.                     
  1389.     Exit:        function result = error code.
  1390.     
  1391.     The caller must allocate and initialize a print record, and call 
  1392.     PrStlDialog to present the page setup dialog and initialize the print
  1393.     record.  rep_Print calls PrJobDialog to present the job dialog.
  1394.     The printing manager should be closed before calling rep_Print.
  1395. _____________________________________________________________________*/
  1396.  
  1397.  
  1398. OSErr rpp_Print (Handle repHandle, Boolean printOne, rpp_PrtBlock *p)
  1399.  
  1400. {
  1401.     ListHandle        theList;                /* handle to list record */
  1402.     OSErr                rCode;                /* print manager error code */
  1403.     Boolean            printOK;                /* true if user said OK in job dialog */
  1404.     GrafPtr            savedPort;            /* saved grafport */
  1405.     short                savedResFile;        /* saved cur res file */
  1406.     short                printingResFile;    /* printing res file */
  1407.     TPPrPort            port;                    /* printing port */
  1408.     TPrStatus        prStatus;            /* printer status record */
  1409.     short                pageNum;                /* current page number */
  1410.     long                secs;                    /* current time */
  1411.     CursHandle        watch;                /* handle to watch cursor */
  1412.     DialogPtr        dlog;                    /* pointer to printing dialog */
  1413.     short                nCopies;                /* number of copies */
  1414.     Boolean            laser;                /* true if laserwriter */
  1415.     short                first;                /* first page number */
  1416.     short                last;                    /* last page number */
  1417.     Str255            firstStr;            /* first page number */
  1418.     Str255            lastStr;                /* last page number */
  1419.     Boolean            canceled;            /* true if canceled by Cmd-Period */
  1420.     Rect                dlogRect;            /* printing in progress dialog rectangle */
  1421.     Boolean            oldRom;                /* true if 64K ROM */
  1422.     
  1423.     PBlock = p;
  1424.     theList = (ListHandle)repHandle;
  1425.     GetPort(&savedPort);
  1426.     savedResFile = CurResFile();
  1427.     TconCompute = 0;
  1428.     
  1429.     /* Enable fractional character widths for better looking 
  1430.         LaserWriter output. */
  1431.     
  1432.     oldRom = utl_Rom64();
  1433.     if (!oldRom) SetFractEnable(true);
  1434.     
  1435.     /* Get current date and time for headers. */
  1436.     
  1437.     if (p->header) {
  1438.         GetDateTime(&secs);
  1439.         IUDateString(secs, shortDate, (StringPtr)&NowDate);
  1440.         IUTimeString(secs, true, (StringPtr)&NowTime);
  1441.     };
  1442.     
  1443.     /* Compute header font size. */
  1444.     
  1445.     laser = utl_IsLaser(p->hPrint);
  1446.     TitleSize = utl_ScaleFontSize(p->fontNum, p->fontSize, p->titleSize, laser); 
  1447.     
  1448.     CalcPrintBox(p->hPrint, p->leftMargin, p->rightMargin, p->topMargin,
  1449.         p->botMargin);
  1450.     
  1451.     if (!(rCode = PrError())) {
  1452.     
  1453.         /* Put up the standard job dialog */
  1454.  
  1455.         if (!printOne) {
  1456.             PrtJobDialog = PrJobInit(p->hPrint);
  1457.             printOK = PrDlgMain(p->hPrint, MyJobDlgInit);
  1458.             rCode = PrError();
  1459.             if (PBlock->updateAll) (*PBlock->updateAll)();
  1460.         } else {
  1461.             printOK = true;
  1462.             (**p->hPrint).prJob.iFstPage = 1;
  1463.             (**p->hPrint).prJob.iLstPage = 999;
  1464.         };
  1465.     
  1466.         /* Print the report. */
  1467.         
  1468.         if (!rCode && printOK) {
  1469.             watch = GetCursor(watchCursor);
  1470.             SetCursor(*watch);
  1471.             printingResFile = CurResFile();
  1472.             UseResFile(savedResFile);
  1473.             UseResFile(printingResFile);
  1474.             dlog = GetNewDialog(p->dlogID, nil, (WindowPtr)-1);
  1475.             dlogRect = dlog->portRect;
  1476.             utl_CenterDlogRect(&dlogRect, p->menuPick);
  1477.             MoveWindow(dlog, dlogRect.left, dlogRect.top, false);
  1478.             SetWTitle((WindowPtr)dlog, (StringPtr)p->docName);
  1479.             ParamText((StringPtr)p->docName, nil, nil, nil);
  1480.             ShowWindow((WindowPtr)dlog);
  1481.             DrawDialog(dlog);
  1482.             first = FirstPage = (**p->hPrint).prJob.iFstPage;
  1483.             last = LastPage = (**p->hPrint).prJob.iLstPage;
  1484.             if (FirstPage <= 1) FirstPage = 1;
  1485.             if (LastPage > 999) LastPage = 999;
  1486.             (**p->hPrint).prJob.iFstPage = 1;
  1487.             (**p->hPrint).prJob.iLstPage = 999;
  1488.             TruncateRight = TruncateBottom = false;
  1489.             if ((**theList).refCon) {
  1490.                 canceled = Break1(theList, p);
  1491.             } else {
  1492.                 canceled = Break0(theList, p);
  1493.             };
  1494.             if (!canceled) {
  1495.                 if (FirstPage > LastPage || TruncateRight || TruncateBottom) {
  1496.                     DisposDialog(dlog);
  1497.                     if (PBlock->updateAll) (*PBlock->updateAll)();
  1498.                     dlog = nil;
  1499.                     InitCursor();
  1500.                     if (FirstPage > LastPage) {
  1501.                         NumToString(first, firstStr);
  1502.                         NumToString(last, lastStr);
  1503.                         ParamText(firstStr, lastStr, nil, nil);
  1504.                         utl_StopAlert(p->emptyPageRangeID, nil, 0);
  1505.                     } else if (TruncateRight) {
  1506.                         utl_StopAlert(p->truncateRightID, nil, 0);
  1507.                     } else if (TruncateBottom) {
  1508.                         utl_StopAlert(p->truncateBottomID, nil, 0);
  1509.                     };
  1510.                 } else {
  1511.                     nCopies = ((**p->hPrint).prJob.bJDocLoop == bDraftLoop && 
  1512.                         !laser) ? (**p->hPrint).prJob.iCopies : 1;
  1513.                     PrValidate(p->hPrint);        /* set doc title - see TN 149 */
  1514.                     while (nCopies--) {
  1515.                         port = PrOpenDoc(p->hPrint, nil, nil);
  1516.                         pageNum = p->reverseOrder ? LastPage : FirstPage;
  1517.                         while (true) {
  1518.                             if (rCode = PrError() || CheckCancel()) break;
  1519.                             if (p->reverseOrder) {
  1520.                                 if (pageNum < FirstPage) break;
  1521.                             } else {
  1522.                                 if (pageNum > LastPage) break;
  1523.                             };
  1524.                             PrOpenPage(port, nil);
  1525.                             if (!(rCode = PrError())) {
  1526.                                 SetPort((GrafPtr)port);
  1527.                                 ClipRect(&PrintBox);
  1528.                                 if ((**theList).refCon) {
  1529.                                     Print1(theList, p, pageNum);
  1530.                                 } else {
  1531.                                     Print0(theList, p, pageNum);
  1532.                                 };
  1533.                             };
  1534.                             PrClosePage(port);
  1535.                             if (p->reverseOrder) {
  1536.                                 pageNum--;
  1537.                             } else {
  1538.                                 pageNum++;
  1539.                             };
  1540.                         };
  1541.                         PrCloseDoc(port);
  1542.                         if (!(rCode = PrError())) {
  1543.                             if ((**p->hPrint).prJob.bJDocLoop == bSpoolLoop) {
  1544.                                 PrPicFile(p->hPrint, nil, nil, nil, &prStatus);
  1545.                                 rCode = PrError();
  1546.                             };
  1547.                         };
  1548.                     };
  1549.                 };
  1550.             };
  1551.             if ((**theList).refCon) {
  1552.                 DisposHandle((Handle)Breaks1);
  1553.             } else {
  1554.                 DisposHandle((Handle)Breaks0);
  1555.             };
  1556.             if (dlog) DisposDialog(dlog);
  1557.             InitCursor();
  1558.         };
  1559.     };
  1560.     
  1561.     SetPort(savedPort);
  1562.     
  1563.     /* Disable fractional character widths. */
  1564.     
  1565.     if (!oldRom) SetFractEnable(false);
  1566.     
  1567.     return PrError();
  1568. }
  1569.  
  1570. /*______________________________________________________________________
  1571.  
  1572.     DrawList - Draw List Manager Dialog User Item.
  1573.     
  1574.     Entry:    theWindow = pointer to page setup dialog.
  1575.                 itemNo = item number.
  1576. _____________________________________________________________________*/
  1577.  
  1578.  
  1579. static pascal void DrawList (WindowPtr theWindow, short itemNo)
  1580.  
  1581. {
  1582.     short            itemType;            /* item type */
  1583.     Handle        item;                    /* item handle */
  1584.     Rect            box;                    /* item rectangle */
  1585.  
  1586.     GetDItem(theWindow, itemNo, &itemType, &item, &box);
  1587.     FrameRect(&box);
  1588.     if (itemNo == FirstItem+fontListItem) {
  1589.         LUpdate((**FontList).port->visRgn, FontList);
  1590.     } else {
  1591.         LUpdate((**SizeList).port->visRgn, SizeList);
  1592.     };
  1593. }
  1594.  
  1595. /*______________________________________________________________________
  1596.  
  1597.     BuildSizeList - Build Font Size List.
  1598.     
  1599.     Entry:        theDialog = pointer to dialog.
  1600. _____________________________________________________________________*/
  1601.  
  1602.  
  1603. static void BuildSizeList (DialogPtr theDialog)
  1604.  
  1605. {
  1606.     short            itemType;        /* item type */
  1607.     Handle        item;                /* item handle */
  1608.     Rect            box;                /* item rectangle */
  1609.     Cell            cell;                /* List Manager cell */
  1610.     short            len;                /* length of font name */
  1611.     Str255        str;                /* multi-purpose string */
  1612.     Str255        str1;                /* current size from size TE box */
  1613.     short            fontNum;            /* font number */
  1614.     short            i;                    /* loop index */
  1615.  
  1616.     LDoDraw(false, SizeList);
  1617.     SetPt(&cell, 0, 0);
  1618.     LGetSelect(true, &cell, FontList);
  1619.     len = 255;
  1620.     LGetCell((Ptr)str+1, &len, cell, FontList);
  1621.     *str = len;
  1622.     GetFNum(str, &fontNum);
  1623.     LDelRow(0, 0, SizeList);
  1624.     SetPt(&cell, 0, 0);
  1625.     GetDItem(theDialog, FirstItem+sizeTEItem, &itemType, &item, &box);
  1626.     GetIText(item, str1);
  1627.     for (i = PBlock->minFontSize; i <= PBlock->maxFontSize; i++) {
  1628.         if (RealFont(fontNum, i)) {
  1629.             LAddRow(1, cell.v, SizeList);
  1630.             NumToString(i, str);
  1631.             LSetCell((Ptr)str+1, *str, cell, SizeList);
  1632.             if (EqualString(str, str1, false, false)) 
  1633.                 LSetSelect(true, cell, SizeList);
  1634.             cell.v++;
  1635.         };
  1636.     };
  1637.     LDoDraw(true,SizeList);
  1638.     if (((WindowPeek)theDialog)->visible) {
  1639.         box = (**SizeList).rView;
  1640.         EraseRect(&box);
  1641.         box.right += 15;
  1642.         InvalRect(&box);
  1643.     };
  1644. }
  1645.  
  1646. /*______________________________________________________________________
  1647.  
  1648.     MyFltrProc - Filter proc for custom page setup dialog.
  1649.     
  1650.     Entry:    theDialog = pointer to dialog.
  1651.                 theEvent = pointer to event record.
  1652.                 itemHit = pointer to item number.
  1653.                 
  1654.     This filter proc validates key presses when one of our extra textedit
  1655.     fields is active.
  1656.     
  1657.     For the font size field, we permit at most 2 digits.
  1658.     
  1659.     For the margin fields, we permit at most 6 characters, consisting
  1660.     of digits and at most one decimal point.
  1661. _____________________________________________________________________*/
  1662.  
  1663.  
  1664. static pascal Boolean MyFltrProc (DialogPtr theDialog, EventRecord *theEvent,
  1665.     short *itemHit)
  1666.     
  1667. {
  1668.     short                key;                /* ascii code of key pressed */
  1669.     short                item;                /* item number of current textedit field */
  1670.     TEHandle            textH;            /* handle to TextEdit record */
  1671.     short                selStart;        /* start of selection range */
  1672.     short                selEnd;            /* end of selection range */
  1673.     short                selSize;            /* size of selected part of item */
  1674.     short                oldSize;            /* old text length */
  1675.     short                newSize;            /* new size of field */
  1676.     Boolean            isdig;            /* true if key is a digit */
  1677.     char                *p;                /* pointer into text */
  1678.     char                *pStart;            /* pointer to beginning of text */
  1679.     char                *pEnd;            /* pointer to end of text */
  1680.     short                pIndex;            /* index in text of decimal point */
  1681.  
  1682.     if (theEvent->what == keyDown || theEvent->what == autoKey) {
  1683.         key = theEvent->message & charCodeMask;
  1684.         if (key != returnKey && key != enterKey && key != deleteKey &&
  1685.             key != tabKey && key != leftArrow && key != rightArrow) {
  1686.             item = ((DialogPeek)theDialog)->editField + 1;
  1687.             if (item > FirstItem) {
  1688.                 item -= FirstItem;
  1689.                 textH = ((DialogPeek)theDialog)->textH;
  1690.                 selStart = (**textH).selStart;
  1691.                 selEnd = (**textH).selEnd;
  1692.                 selSize = selEnd - selStart;
  1693.                 oldSize = (**textH).teLength;
  1694.                 newSize = oldSize + 1 - selSize;
  1695.                 isdig = isdigit(key);
  1696.                 if (item == sizeTEItem) {
  1697.                     if (isdig && newSize <= 2) return false;
  1698.                 } else {
  1699.                     if (newSize <= 6) {
  1700.                         if (isdig) return false;
  1701.                         if (key == '.') {
  1702.                             pStart = p = *(**textH).hText;
  1703.                             pEnd = p + oldSize;
  1704.                             while (p < pEnd && *p != '.') p++;
  1705.                             if (p == pEnd) return false;
  1706.                             pIndex = p - pStart;
  1707.                             if (pIndex >= selStart && pIndex < selEnd) return false;
  1708.                         };
  1709.                     };
  1710.                 };
  1711.                 SysBeep(10);
  1712.                 theEvent->what = nullEvent;
  1713.                 return false;
  1714.             };
  1715.         };
  1716.     };
  1717.     if (StdFltrProc) {
  1718.         return (*StdFltrProc)(theDialog, theEvent, itemHit);
  1719.     } else {
  1720.         return false;
  1721.     };
  1722. }
  1723.  
  1724. /*______________________________________________________________________
  1725.  
  1726.     MyItemProc - Handle custom page setup item hit.
  1727.     
  1728.     Entry:    hPrint = handle to print record.
  1729.     
  1730.     Exit:        function result = pointer to print dialog stream object.
  1731. _____________________________________________________________________*/
  1732.  
  1733.  
  1734. static pascal void MyItemProc (DialogPtr theDialog, short itemNo)
  1735.  
  1736. {
  1737.     short                itemType;        /* item type */
  1738.     Handle            item;                /* item handle */
  1739.     Rect                box;                /* item rectangle */
  1740.     Str255            str;                /* multi-purpose string */
  1741.     Str255            str1;                /* second string */
  1742.     unsigned char    *pstr;            /* pointer to cur pos in string */
  1743.     unsigned char    lstr;                /* length of string */
  1744.     long                val;                /* value of string */
  1745.     short                i;                    /* loop index */
  1746.     short                whole;            /* whole part of decimal number */
  1747.     short                frac;                /* fraction part of decimal number */
  1748.     unsigned char    *point;            /* pointer to decimal point in string */
  1749.     short                margin;            /* margin value in 1/100 inches */
  1750.     Point                where;            /* location of mouse click */
  1751.     Cell                cell;                /*    old selected List Manager cell */
  1752.     Cell                newCell;            /* new selected List Manager cell */
  1753.     short                len;                /* length of selected font name */
  1754.     short                fontNum;            /* font number */
  1755.     short                fontSize;        /* font size */
  1756.     short                topMargin;        /* top margin */
  1757.     short                botMargin;        /* bottom margin */
  1758.     short                leftMargin;        /* left margin */
  1759.     short                rightMargin;    /* right margin */
  1760.     
  1761.     if (itemNo > FirstItem) {
  1762.     
  1763.         /* Process a hit on one of our extra dialog items. */
  1764.     
  1765.         GetDItem(theDialog, itemNo, &itemType, &item, &box);
  1766.         switch (itemNo - FirstItem) {
  1767.             case reverseItem:
  1768.                 SetCtlValue((ControlHandle)item, 1 - GetCtlValue((ControlHandle)item));
  1769.                 break;
  1770.             case fontListItem:
  1771.                 SetPort(theDialog);
  1772.                 SetPt(&cell, 0, 0);
  1773.                 LGetSelect(true, &cell, FontList);
  1774.                 GetMouse(&where);
  1775.                 LClick(where, 0, FontList);
  1776.                 SetPt(&newCell, 0, 0);
  1777.                 if (LGetSelect(true, &newCell, FontList)) {
  1778.                     if (cell.v != newCell.v) BuildSizeList(theDialog);
  1779.                 } else {
  1780.                     LSetSelect(true, cell, FontList);
  1781.                 };
  1782.                 break;
  1783.             case sizeListItem:
  1784.                 SetPort(theDialog);
  1785.                 GetMouse(&where);
  1786.                 LClick(where, 0, SizeList);
  1787.                 SetPt(&cell, 0, 0);
  1788.                 if (LGetSelect(true, &cell, SizeList)) {
  1789.                     len = 255;
  1790.                     LGetCell((Ptr)str+1, &len, cell, SizeList);
  1791.                     *str = len;
  1792.                     GetDItem(theDialog, FirstItem+sizeTEItem, &itemType,
  1793.                         &item, &box);
  1794.                     SetIText(item, str);
  1795.                 };
  1796.                 break;
  1797.         };
  1798.         
  1799.     } else {
  1800.     
  1801.         /* Process a hit on the standard OK button. */
  1802.     
  1803.         if (itemNo == OK) {
  1804.         
  1805.             /* Fetch the font. */
  1806.             
  1807.             SetPt(&cell, 0, 0);
  1808.             LGetSelect(true, &cell, FontList);
  1809.             len = 255;
  1810.             LGetCell((Ptr)str+1, &len, cell, FontList);
  1811.             *str = len;
  1812.             GetFNum(str, &fontNum);
  1813.                 
  1814.             /* Fetch and validate the font size. */
  1815.         
  1816.             GetDItem(theDialog, FirstItem+sizeTEItem, &itemType, 
  1817.                 &item, &box);
  1818.             GetIText(item, str);
  1819.             StringToNum(str, &val);
  1820.             if (val < PBlock->minFontSize || val > PBlock->maxFontSize) {
  1821.                 NumToString(PBlock->minFontSize, str);
  1822.                 NumToString(PBlock->maxFontSize, str1);
  1823.                 ParamText(str, str1, nil, nil);
  1824.                 utl_StopAlert(PBlock->sizeRangeID, nil, 0);
  1825.                 SelIText(theDialog, FirstItem+sizeTEItem, 0, 32767);
  1826.                 return;
  1827.             };
  1828.             fontSize = val; 
  1829.         
  1830.             /* Fetch and evaluate the four margins. */
  1831.             
  1832.             for (i = 0; i < 4; i++) {
  1833.                 GetDItem(theDialog, FirstItem+leftTEItem+i, &itemType, 
  1834.                     &item, &box);
  1835.                 GetIText(item, str);
  1836.                 pstr = str+1;
  1837.                 lstr = *str;
  1838.                 while (lstr) {
  1839.                     if (*pstr == '.') break;
  1840.                     pstr++;
  1841.                     lstr--;
  1842.                 };
  1843.                 *str1 = pstr-str-1;
  1844.                 memcpy(str1+1, str+1, *str1);
  1845.                 StringToNum(str1, &val);
  1846.                 whole = val;
  1847.                 frac = 0;
  1848.                 if (lstr) {
  1849.                     point = pstr;
  1850.                     pstr++;
  1851.                     lstr--;
  1852.                     *str1 = 2;
  1853.                     *(str1+1) = '0';
  1854.                     *(str1+2) = '0';
  1855.                     if (lstr) {
  1856.                         *(str1+1) = *(point+1);
  1857.                         if (lstr > 1) *(str1+2) = *(point+2);
  1858.                     };
  1859.                     StringToNum(str1, &val);
  1860.                     frac = val;
  1861.                 };
  1862.                 margin = 100*whole + frac;
  1863.                 switch (i) {
  1864.                     case 0: leftMargin = margin; break;
  1865.                     case 1: rightMargin = margin; break;
  1866.                     case 2: topMargin = margin; break;
  1867.                     case 3: botMargin = margin; break;
  1868.                 };
  1869.             };
  1870.             
  1871.             /* Check for margins too big.  We require at least 5 inches
  1872.                 of printing area both horizontally and vertically. */
  1873.             
  1874.             CalcPrintBox(PBlock->hPrint, leftMargin, rightMargin, topMargin, botMargin);
  1875.             if (PrintBoxWidth < 5*(**PBlock->hPrint).prInfo.iHRes) {
  1876.                 utl_StopAlert(PBlock->marginsTooBigID, nil, 0);
  1877.                 SelIText(theDialog, FirstItem+leftTEItem, 0, 32767);
  1878.                 return;
  1879.             } else if (PrintBoxHeight < 5*(**PBlock->hPrint).prInfo.iVRes) {
  1880.                 utl_StopAlert(PBlock->marginsTooBigID, nil, 0);
  1881.                 SelIText(theDialog, FirstItem+topTEItem, 0, 32767);
  1882.                 return;
  1883.             };
  1884.         
  1885.             /* Set the new values of the print record fields. */
  1886.             
  1887.             PBlock->fontNum = fontNum;
  1888.             PBlock->fontSize = fontSize;
  1889.             PBlock->topMargin = topMargin;
  1890.             PBlock->botMargin = botMargin;
  1891.             PBlock->leftMargin = leftMargin;
  1892.             PBlock->rightMargin = rightMargin;
  1893.             GetDItem(theDialog, FirstItem+reverseItem, &itemType, &item, &box);
  1894.             PBlock->reverseOrder = GetCtlValue((ControlHandle)item);
  1895.             
  1896.         };
  1897.         
  1898.         /* Call the standard item handler. */
  1899.         
  1900.         (*StdItemProc)(theDialog, itemNo);
  1901.         
  1902.     };
  1903. }
  1904.  
  1905. /*______________________________________________________________________
  1906.  
  1907.     MyStlDlgInit - Initialize custom page setup dialog.
  1908.     
  1909.     Entry:    hPrint = handle to print record.
  1910.     
  1911.     Exit:        function result = pointer to print dialog stream object.
  1912. _____________________________________________________________________*/
  1913.  
  1914.  
  1915. static pascal TPPrDlg MyStlDlgInit (THPrint hPrint)
  1916.  
  1917. {
  1918.     DialogPtr        theDialog;        /* pointer to dialog */
  1919.     short                itemType;        /* item type */
  1920.     Handle            item;                /* item handle */
  1921.     Rect                box;                /* item rectangle */
  1922.     Str255            str;                /* multi-purpose string */
  1923.     Str255            str1;                /* second multi-purpose string */
  1924.     short                i;                    /* loop index */
  1925.     short                val;                /* value */
  1926.     short                whole;            /* whole part of decimal num */
  1927.     short                frac;                /* fraction part of decimal num */
  1928.     unsigned char    len;                /* length of string */
  1929.     Boolean            laser;            /* true if laserwriter */
  1930.     MenuHandle        tempMenu;        /* tempory menu for enumerating fonts */
  1931.     short                numFonts;        /* number of fonts */
  1932.     Rect                dataBounds;        /* dimensions of font list */
  1933.     Point                cSize;            /* font list cell size */
  1934.     Cell                cell;                /* list manager cell */
  1935.     Rect                dlogRect;        /* dialog rectangle */
  1936.     
  1937.     theDialog = (DialogPtr)PrtStlDialog;
  1938.     laser = utl_IsLaser(hPrint);
  1939.     
  1940.     /* Append our extra dialog items. */
  1941.     
  1942.     FirstItem = utl_AppendDITL(theDialog, PBlock->ditlID) - 1;
  1943.     
  1944.     /* Center the dialog. */
  1945.     
  1946.     dlogRect = theDialog->portRect;
  1947.     utl_CenterDlogRect(&dlogRect, PBlock->menuPick);
  1948.     MoveWindow(theDialog, dlogRect.left, dlogRect.top, false);
  1949.     
  1950.     /* Initialize line separator user item. */
  1951.     
  1952.     GetDItem(theDialog, FirstItem+sepLineItem, &itemType, &item, &box);
  1953.     SetDItem(theDialog, FirstItem+sepLineItem, itemType, 
  1954.         (Handle)utl_FrameItem, &box);
  1955.         
  1956.     /* Initialize font list user item.  See TN 191. */
  1957.         
  1958.     GetDItem(theDialog, FirstItem+fontListItem, &itemType, &item, &box);
  1959.     SetDItem(theDialog, FirstItem+fontListItem, itemType, 
  1960.         (Handle)DrawList, &box);
  1961.     GetFontName(PBlock->fontNum, str);
  1962.     if (!*str) GetFontName(applFont, str);
  1963.     tempMenu = NewMenu(9999, (StringPtr)"\px");
  1964.     AddResMenu(tempMenu, 'FONT');
  1965.     numFonts = CountMItems(tempMenu);
  1966.     InsetRect(&box, 1, 1);
  1967.     box.right -= 15;
  1968.     SetRect(&dataBounds, 0, 0, 1, numFonts);
  1969.     SetPt(&cSize, 0, 0);
  1970.     FontList = LNew(&box, &dataBounds, cSize, 0, theDialog, false, false,
  1971.         false, true);
  1972.     LDoDraw(false, FontList);
  1973.     (**FontList).selFlags = lOnlyOne;
  1974.     SetPt(&cell, 0, 0);
  1975.     for (i = 1; i <= numFonts; i++) {
  1976.         GetItem(tempMenu, i, str1);
  1977.         LSetCell((Ptr)str1+1, *str1, cell, FontList);
  1978.         if (EqualString(str, str1, false, false)) {
  1979.             LSetSelect(true, cell, FontList);
  1980.             LAutoScroll(FontList);
  1981.         };
  1982.         cell.v++;
  1983.     };
  1984.     DisposeMenu(tempMenu);
  1985.     LDoDraw(true, FontList);
  1986.         
  1987.     /* Initialize size text edit item. */
  1988.     
  1989.     GetDItem(theDialog, FirstItem+sizeTEItem, &itemType, &item, &box);
  1990.     NumToString(PBlock->fontSize, str);
  1991.     SetIText(item, str);
  1992.     
  1993.     /* Initialize font size list user item. */
  1994.     
  1995.     GetDItem(theDialog, FirstItem+sizeListItem, &itemType, &item, &box);
  1996.     SetDItem(theDialog, FirstItem+sizeListItem, itemType,
  1997.         (Handle)DrawList, &box);
  1998.     InsetRect(&box, 1, 1);
  1999.     box.right -= 15;
  2000.     SetRect(&dataBounds, 0, 0, 1, 0);
  2001.     SetPt(&cSize, 0, 0);
  2002.     SizeList = LNew(&box, &dataBounds, cSize, 0, theDialog, false, false,
  2003.         false, true);
  2004.     (**SizeList).selFlags = lOnlyOne;
  2005.     BuildSizeList(theDialog);
  2006.         
  2007.     /* Initialize reverse order checkbox. */
  2008.     
  2009.     GetDItem(theDialog, FirstItem+reverseItem, &itemType, &item, &box);
  2010.     SetCtlValue((ControlHandle)item, PBlock->reverseOrder);
  2011.     
  2012.     /* Initialize margin text edit items. */
  2013.     
  2014.     for (i = 0; i < 4; i++) {
  2015.         switch (i) {
  2016.             case 0: val = PBlock->leftMargin; break;
  2017.             case 1: val = PBlock->rightMargin; break;
  2018.             case 2: val = PBlock->topMargin; break;
  2019.             case 3: val = PBlock->botMargin; break;
  2020.         };
  2021.         whole = val/100;
  2022.         frac = val%100;
  2023.         NumToString(whole, str);
  2024.         NumToString(frac, str1);
  2025.         if (*str1 == 1) {
  2026.             *str1 = 2;
  2027.             *(str1+2) = *(str1+1);
  2028.             *(str1+1) = '0';
  2029.         };
  2030.         len = *str;
  2031.         *(str+len+1) = '.';
  2032.         memcpy(str+len+2, str1+1, *str1);
  2033.         *str += *str1 + 1;
  2034.         GetDItem(theDialog, FirstItem+leftTEItem+i, &itemType, &item, &box);
  2035.         SetIText(item, str);
  2036.     };
  2037.     
  2038.     /* Save standard item handler and filterproc addresses, and patch in the addresses
  2039.         of our item handler and filterproc. */ 
  2040.         
  2041.     StdItemProc = PrtStlDialog->pItemProc;
  2042.     StdFltrProc = PrtStlDialog->pFltrProc;
  2043.     PrtStlDialog->pItemProc = (ProcPtr)MyItemProc;
  2044.     PrtStlDialog->pFltrProc = (ProcPtr)MyFltrProc;
  2045.     
  2046.     /* Return. */
  2047.         
  2048.     return PrtStlDialog;
  2049. }
  2050.  
  2051. /*______________________________________________________________________
  2052.  
  2053.     rpp_StlDlog - Present Customized Page Setup Dialog.
  2054.     
  2055.     Entry:    p = pointer to parameter block, with fields set as follows:
  2056.     
  2057.                 hPrint = handle to print record.
  2058.                 fontNum = font number.
  2059.                 fontSize = font size.
  2060.                 topMargin = top margin, in 1/100 inch.
  2061.                 botMargin = bottom margin, in 1/100 inch.
  2062.                 leftMargin = left margin, in 1/100 inch.
  2063.                 rightMargin = right margin, in 1/100 inch.
  2064.                 reverseOrder = true if pages to be printed in reverse order.
  2065.                 ditlID = resource id of DITL to be appended to standard
  2066.                     page setup dialog.
  2067.                 sizeRangeID = resource id of font size range error alert.
  2068.                 marginsTooBigID = page margins too big alert.
  2069.                 minFontSize = min legal font size.
  2070.                 maxFontSize = max legal font size.
  2071.                 menuPick = true if Page Setup command was via menu pick, 
  2072.                     false if command key used.
  2073.                     
  2074.     Exit:        canceled = true if Cancel button clicked, 
  2075.                     false if OK button clicked.
  2076.                 function result = error code.
  2077.                     
  2078.                 Following fields are updated in parameter block if the OK button
  2079.                 was clicked:
  2080.                     
  2081.                 fontNum = font number.
  2082.                 fontSize = font size.
  2083.                 topMargin = top margin, in 1/100 inch.
  2084.                 botMargin = bottom margin, in 1/100 inch.
  2085.                 leftMargin = left margin, in 1/100 inch.
  2086.                 rightMargin = right margin, in 1/100 inch.
  2087.                 reverseOrder = true if pages to be printed in reverse order.
  2088. _____________________________________________________________________*/
  2089.  
  2090.  
  2091. OSErr rpp_StlDlog (rpp_PrtBlock *p, Boolean *canceled)
  2092.  
  2093. {
  2094.     Boolean         okClicked;                /* true if OK clicked */
  2095.     OSErr            rCode;                    /* result code */
  2096.  
  2097.     PBlock = p;
  2098.     FontList = nil;
  2099.     SizeList = nil;
  2100.     PrtStlDialog = PrStlInit(p->hPrint);
  2101.     if (rCode = PrError()) return rCode;
  2102.     okClicked = PrDlgMain(p->hPrint, MyStlDlgInit);
  2103.     if (FontList) {
  2104.         (**FontList).vScroll = nil;
  2105.         LDispose(FontList);
  2106.     };
  2107.     if (SizeList) {
  2108.         (**SizeList).vScroll = nil;
  2109.         LDispose(SizeList);
  2110.     };
  2111.     *canceled = !okClicked;
  2112.     return PrError();
  2113. }
  2114.